package com.gframework.paramparse.points;

import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;

import com.gframework.datastructure.trie.WildcardTrieTree;
import com.gframework.datastructure.trie.WildcardTrieTree.ProcessResult;
import com.gframework.paramparse.core.ParamParser;

/**
 * 点段式参数解析器存储树.<br>
 * 这是一个多叉树结构，用于有规律的存储大量的解析器以便于能够最快速的找出准确的解析器去解析。
 * 本类是可变的，且线程安全的
 * </p>
 *
 * @since 1.0.0
 * @author Ghwolf
 * @see ParamParser
 * @see PointSegParserTree
 * @see WildcardTrieTree
 */
class PointSegParserTree {
	/**
	 * 参数解析器存储树
	 */
	private WildcardTrieTree<PointSegParamParser> trie = new WildcardTrieTree<>();

	/**
	 * 参数查询缓存
	 */
	private ConcurrentReferenceHashMap<String, ProcessResult<PointSegParamParser>> cache = new ConcurrentReferenceHashMap<>(
			32, ReferenceType.SOFT);

	/**
	 * 最大缓存多长的参数
	 */
	private static final int CACHE_MAX_PARAM_LENGTH = 16;

	/**
	 * 取得经过格式化梳妆结构字符图.<br>
	 * 此方法主要用于日志输出
	 * 
	 * @return 返回格式化后的树状结构图
	 */
	public String getFormatLeaf() {
		return this.trie.getFormatString("参数解析器结构图");
	}

	/**
	 * 本方法可以根据优先级寻找一个最适合的解析器去处理，如果没有找到，则返回null
	 * 
	 * @param param 要查询的参数
	 * @return 如果由可以处理的解析器，则返回一个包含了value和通配符匹配key的对象，返回对象一定不是null，但是value可能是null
	 */
	public ProcessResult<PointSegParamParser> find(String param) {
		boolean canCache = param.length() <= CACHE_MAX_PARAM_LENGTH;
		if (canCache) {
			ProcessResult<PointSegParamParser> t = this.cache.get(param);
			if (t != null) return t;
		}

		ProcessResult<PointSegParamParser> result = this.trie.findProcessResult(param);
		if (result.getValue() != null && canCache && result.getValue().allowCache()) {
			this.cache.put(param, result);
		}
		return result;
	}

	/**
	 * 根据解析格式信息生成一个新的树节点用于处理新的参数解析。
	 * <strong>注意：本方法不做参数合法性验证，如果调用处不经过合理参数验证，可能会导致不可预料的错误！</strong>
	 * 
	 * @param parser 解析格式信息
	 */
	void createNode(String analyticFormat, PointSegParamParser paramParser) {
		PointSegParamParser old = this.trie.add(analyticFormat, paramParser);
		if (old != null) {
			throw new ParserTreeInitException("出现了重复的参数解析表达式：" + analyticFormat);
		}
	}
}
